What are the most frequent minor variants in the high-confidence samples?

source("./scripts/startup.R")
The following packages are a base install and will not be unloaded:



The following packages were not previously loaded:



Loading required package: pacman
patient_var_30 = read_feather("processing/patient_var_30.arrow")
maf_histogram = patient_var_30 %>% ggplot(aes(minorfreq)) + geom_histogram(binwidth = 0.01) + theme_pubr()
quantile(patient_var_30$minorfreq, probs = c(.25,.5,.75), na.rm = T)
       25%        50%        75% 
0.01252470 0.01717647 0.02788318 
ggsave("ggsave/maf_histogram.pdf", maf_histogram, width = 3, height = 3)

patient_var_30_for_rank = patient_var_30 %>% drop_na(gene) %>% filter(gene !="") %>%
  mutate(label = paste0(ref_sym, aapos), 
         refnt = str_sub(ref_codon, start = codon_pos, end = codon_pos))
bp = c("A", "T", "C", "G")
lineage_defining_mutations = fread("20220103-TRACE-LineageDefinitions-v9.1.txt", data.table = F) %>%
  filter(nt_ref %in% bp & 
           nt_alt %in% bp & 
           variation_type == "SNP") %>% select(nt_pos, nt_ref, nt_alt)
ldm_map = patient_var_30_for_rank %>% 
  mutate(ldm  = ifelse(ntpos %in% lineage_defining_mutations$nt_pos, TRUE, FALSE)) %>% 
  select(gene, label, ldm) %>% distinct %>% group_by(gene, label) %>% arrange(-ldm) %>%
  filter(row_number()==1)
  

highly_shared_sites_ranked = patient_var_30_for_rank %>% drop_na(gene) %>% filter(gene !="") %>%
  mutate(label = paste0(ref_sym, aapos), 
         refnt = str_sub(ref_codon, start = codon_pos, end = codon_pos)) %>%
  group_by(mcov_id, gene, label) %>%
  tally() %>% 
  arrange(-n) %>% ungroup %>% group_by(gene, label) %>% 
  summarize(label_count = n()) %>% ungroup() %>% arrange(-label_count) %>% mutate(rank = 1:nrow(.)) %>%
  left_join(ldm_map) %>% unique()

# highly_shared_sites_ranked_50 = highly_shared_sites_ranked %>% filter(rank <= 25)
# 
# ((
#   hss_maf_50<-patient_var_30 %>% filter(paste0(gene, aapos) %in% paste0(highly_shared_sites_ranked_50$gene, parse_number(highly_shared_sites_ranked_50$label))) %>% 
#     ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
#     #geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
#     geom_boxplot(outlier.shape = NA, alpha =0.5) + theme_bw() +
#     theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
#     xlab("Nucleotide position") + ylab("Minor allele freq") ))
# 
# ggsave("ggsave/hss_maf_50.pdf", hss_maf_50, width = 5, height = 3)


#%>% 
 # left_join(patient_var_30 %>% select(ntpos, gene, ref_sym, aapos, ref_codon, codon_pos) %>% distinct)

# ((
#   highly_shared_sites<- patient_var_30 %>% group_by(ntpos) %>% tally() %>% arrange(desc(n)) %>% 
#        drop_na(ntpos) %>% slice_max(n, n = 35) %>% pull(ntpos) %>% as.numeric()
# ))


sample_n = length(unique(patient_var_30$mcov_id))
#for (this_gene in gene_limits$gene_id) {
  plot_ranks = highly_shared_sites_ranked %>% filter(rank <= 35) %>% 
    ggplot(aes(rank, label_count, label = label)) + 
  geom_line(data = highly_shared_sites_ranked %>% 
              select(!gene) %>% filter(rank <= 35), aes(rank, label_count), color = "grey") +
  scale_y_continuous(trans = "log2", breaks = 2^seq(0,12,1),
                     sec.axis = sec_axis(~./sample_n, labels = scales::label_percent(),
                                           breaks = 2^seq(0,8,1)/100)) + theme_pubr() +
  geom_point(aes(rank, label_count), color = "grey") +
  geom_text_repel(aes(label = label, color = ldm), ylim = c(6,11), xlim = c(NA, NA), angle = 90,
                  segment.size = 0.6, segment.curvature = -1e-20, segment.linetype = 3,
                  max.overlaps = Inf) + coord_cartesian(clip = "off") +
    scale_color_manual(values = c("salmon", "grey")) +
    facet_wrap(~gene)
  
  plot_ranks
#}
ggsave("ggsave/plot_ranks.pdf", plot_ranks, height = 5.5, width = 7)

# Across genome


lineage_defining_mutations

plot_data_LDM_prop = patient_var_30 %>% group_by(MCoVNumber) %>% drop_na(ntpos) %>% 
  summarize(iSNV_count = n(), iSNV = paste0(ntpos, collapse = ","), 
            iSNV_LDM_count = length(ntpos[ntpos %in% lineage_defining_mutations$nt_pos]),
            iSNV_LDM = paste0(ntpos[ntpos %in% lineage_defining_mutations$nt_pos],
                              collapse = ","), prop = iSNV_LDM_count/iSNV_count)

plot_data_LDM_prop %>% ggplot(aes(as.factor(iSNV_count), prop)) + geom_violin(draw_quantiles=c(0.5))

patient_var_30_reversions = patient_var_30 %>% mutate(reversion = minor == str_sub(ref_codon, 
                            start = codon_pos, end = codon_pos)) %>% drop_na(reversion)

# How many of our alleles were reversions?
patient_var_30_reversions %>% summarize(proportion_reversion = sum(reversion==T)/
                                          nrow(patient_var_30))

# How many of our alleles that are reversions are at LDM sites?
patient_var_30_reversions %>% mutate(ldm = ifelse(ntpos %in% lineage_defining_mutations$nt_pos,1,0)) %>% 
  summarize(proportion_reversion = sum(ldm == 1 & reversion == T)/sum(reversion==T))

# obscure the consensus in the VCF
problem_sites_global = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
  filter(FILTER != "mask") %>%
  filter(!grepl('single_src|nanopore', INFO)) %>% pull(POS)
problem_sites_houston = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88) %>%
  filter(grepl('Houston', INFO)) %>% pull(POS)
problem_sites = unique(c(problem_sites_global, problem_sites_houston))
problem_sites
 [1]    76    78   320   538   660  1001  1814  1947  2087  5393  5498  6309  6310  6312  6866  7396
[17] 12685 13512 13513 13514 13686 13693 18505 18506 19338 19344 19369 19732 21302 21304 21305 21658
[33] 22393 22410 22488 22515 23144 24673 25798 26709 27792 28881 28882 28883 29378  8658 12698 15103
[49] 16130 16132 22892
# UNCOMMENT BELOW IF NECESSARY TO REGENERATE DATA
# consensus <-fread("consensus_minor_changes_20220713.csv", data.table = F) %>% filter(!ntpos %in% problem_sites) %>% filter(!ntpos %in% c(1:265)) %>% filter(!ntpos>29674)
# 
# 
# 
# consensus 
# 
# #
# consensus_count = consensus %>% 
#   mutate(MCoVNumber = mcov_reformat(name)) %>% 
#   select(MCoVNumber, major, ntpos, refnt) %>% 
#   filter(major != refnt) %>% 
#   unique() %>%
#   group_by(ntpos) %>%
#   summarize(MCoVNumber = unique(MCoVNumber)) 
# 
# runs = fread("sample_date_and_run.csv", data.table = F) %>%
#     mutate(MCoVNumber = mcov_reformat(mcov_id))
# 
# consensus_runs = consensus_count %>% left_join(runs) %>% drop_na() %>%
#   select(ntpos, MCoVNumber_possible_contaminant = MCoVNumber, run_consensus = run_group) #has each of the consensus mutations with the MCOV
# 
# # uncomment below if necessary
# #patient_var_30_contaminated = patient_var_30 %>% left_join(consensus_runs) # intensive
# #write_feather(patient_var_30_contaminated, "processing/patient_var_30_contaminated.arrow")
# 
patient_var_30_contaminated = read_feather("processing/patient_var_30_contaminated.arrow")
contaminated_df = patient_var_30_contaminated %>% mutate(ref_nt = str_sub(ref_codon,
                            start = codon_pos, end = codon_pos)) %>%
  select(MCoVNumber, run_group, ntpos, ref_nt, major, minor, MCoVNumber_possible_contaminant, run_consensus)

contaminated_df_tallied = contaminated_df %>%
  filter(run_group == run_consensus) %>%
  group_by(MCoVNumber) %>%
  summarize(n_var_contam = length(unique(ntpos)), MCoVNumber_possible_contaminant) %>%
  group_by(MCoVNumber, MCoVNumber_possible_contaminant) %>%
  summarize(n_var_contam, single_sample = n(), prop_single_sample = single_sample / n_var_contam)
`summarise()` has grouped output by 'MCoVNumber'. You can override using the `.groups` argument.`summarise()` has grouped output by 'MCoVNumber', 'MCoVNumber_possible_contaminant'. You can override using the `.groups` argument.
contaminated_df_tallied_top = contaminated_df_tallied %>% group_by(MCoVNumber) %>% top_n(n=1) %>%
  filter(row_number()==1)
Selecting by prop_single_sample
#Note prop_single_sample is single_sample / n_var_contam (proportion of number of minor variants that resememble consensus in another sample / number of minor variants that resemble any consensus in the run)
# prop single contam is the same as above but the denom is out of n_var
patient_counts_30 = read_feather("processing/patient_counts_30.arrow")
patient_counts_30_anno = patient_counts_30 %>% left_join(contaminated_df_tallied_top) %>%
  mutate(run_num = as.numeric(str_replace(run_group, "Run_", ""))) %>%
  replace(is.na(.),0)
Joining, by = "MCoVNumber"
# Plot: n_var x prob that it's from a single source
plot_contam = patient_counts_30_anno %>% mutate(prop_contam = n_var_contam/n_var, prop_single_contam = single_sample/n_var) 

plot_contam %>% select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  pivot_longer(cols= c(prop_contam, prop_single_contam), names_to = "type", values_to = "prop")  %>%
  ggplot(aes(x = admitted_hospital, y = prop, 
             fill = type)) + 
  geom_violin(draw_quantiles = c(0.25,0.5,0.75))


median_contam_contam = quantile(plot_contam %>% filter(n_var > 0) %>% 
                                  pull(prop_contam), probs = c(0.5))
print(median_contam_contam)
50% 
0.5 
plot_contam_contam = plot_contam %>% 
  select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  ggplot(aes(x = n_var, y = prop_contam, 
             fill = admitted_hospital, color = admitted_hospital)) + 
  geom_point(alpha = 0.02) + geom_smooth() + theme_pubr() +
  geom_hline(yintercept = median_contam_contam, linetype = "dashed")

plot_contam_contam = ggMarginal(plot_contam_contam, groupColour = T, groupFill = T, type = "violin",
           draw_quantiles = c(0.25, 0.5, 0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).Warning: Removed 450 rows containing missing values (`geom_point()`).
median_single_contam = quantile(plot_contam %>% filter(n_var > 0) %>% 
                                  pull(prop_single_contam), probs = c(0.5))
print(median_single_contam)
      50% 
0.3333333 
plot_contam_single_contam = plot_contam %>% 
  select(n_var, admitted_hospital, prop_contam, prop_single_contam) %>% 
  ggplot(aes(x = n_var, y = prop_single_contam, 
             fill = admitted_hospital, color = admitted_hospital)) + 
  geom_point(alpha = 0.02) + geom_smooth() + theme_pubr() + 
  geom_hline(yintercept = median_single_contam, linetype = "dashed")

plot_contam_single_contam = ggMarginal(plot_contam_single_contam, 
                                       groupColour = T, groupFill = T, 
                                       type = "violin",
           draw_quantiles = c(0.25, 0.5, 0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 450 rows containing non-finite values (`stat_smooth()`).Warning: Removed 450 rows containing missing values (`geom_point()`).
plot_contam_arranged = ggarrange(plot_contam_contam, plot_contam_single_contam,
                                 align = "v",
                                 labels = "AUTO")
plot_contam_arranged
ggsave("ggsave/plot_contam_arranged.pdf", plot_contam_arranged, height = 3, width = 6)

#consensus_sites_lowct %>% filter(refnt == major)
patient_counts_30 = read_feather("processing/patient_counts_30.arrow")


# criteria to count the mutation
# consensus = if ntpos matches in the list above, then 
# the minor will also match the nt_ref (i.e. reversion) or the nt_alt


ldm = c(paste0(lineage_defining_mutations$nt_alt,
                                      lineage_defining_mutations$nt_pos,
                                      lineage_defining_mutations$nt_ref),
                               paste0(lineage_defining_mutations$nt_ref,
                                      lineage_defining_mutations$nt_pos,
                                      lineage_defining_mutations$nt_alt))
        
minor_consensus_plotdata = patient_var_30 %>% #left_join(consensus) %>% 
    mutate(ref_nt = str_sub(ref_codon, 
                            start = codon_pos, end = codon_pos),
      ref_mutation = paste0(ref_nt, ntpos, minor),
      mutation = paste0(major, ntpos, minor), consensus = 
             ifelse(ntpos %in% lineage_defining_mutations$nt_pos, 
                    ifelse((mutation %in% ldm) | (ref_mutation %in% ldm),
                           TRUE, FALSE),      
                           FALSE)) %>% #filter(consensus == FALSE) %>%
  group_by(ntpos, consensus) %>% 
  summarize(consensus = consensus, n = n()) %>%
  unique %>% drop_na %>% ungroup %>% arrange(-n) %>%
  mutate(rank = 1:nrow(.))
`summarise()` has grouped output by 'ntpos', 'consensus'. You can override using the `.groups` argument.
minor_prevalence_across_genome_unlog <- minor_consensus_plotdata  %>%
    ggplot(aes(x = ntpos, y = n, fill = consensus, color = consensus)) + 
    # label your data too for the SALMON
    geom_bar(stat = "identity") + 
  scale_color_manual(values = c("salmon","grey")) + scale_fill_manual(values = c("salmon","grey")) +
    
      geom_point( aes(x = ntpos, y= n), shape = "") +
    #scale_color_manual(values = c("salmon","black")) + 
  theme_bw() + 
  geom_hline(yintercept = nrow(patient_counts_30)*0.01, linetype="dotted") + 
  xlab("Nucleotide position") + ylab("No. samples w/minor variant at site") + 
  annotate("rect", xmin=27894, xmax=28295, ymin=0, ymax=Inf, alpha=0.2, fill="#85D4E3") + 
  annotate("rect", xmin=28274, xmax=29533, ymin=0, ymax=Inf, alpha=0.2, fill="#F4B5BD") + 
  annotate("rect", xmin=21563, xmax=25384, ymin=0, ymax=Inf, alpha=0.2, fill="#FAD77B") +  xlim(0,29903)

minor_prevalence_across_genome_unlog


minor_prevalence_across_genome_unlog_labeled = 
  minor_prevalence_across_genome_unlog + 
  geom_text_repel(max.overlaps = Inf, ylim  = c(500,NA), size = 3, angle = 90, 
                  segment.linetype = 3, segment.size = 0.6, 
                  segment.curvature = -1e-20, 
                  arrow = arrow(length = unit(0.015, "npc"), 
                                type = "closed"),
                  data = minor_consensus_plotdata %>%
                    filter(rank < 50),
                    aes(x = ntpos, y = n, label = ntpos, color = consensus, fill = consensus))
Warning: Ignoring unknown aesthetics: fill
minor_prevalence_across_genome_unlog_labeled


genes <- fread("ntpos_gene_update.csv", data.table = F)

gene_limits<- genes %>% group_by(gene_id) %>% summarise(start=min(ntpos), end=max(ntpos)) %>% filter(gene_id!="") %>% mutate(molecule="")

gene_arrows<-ggplot(gene_limits, aes(xmin = start, xmax = end, y=molecule, label = gene_id)) +
  geom_gene_arrow(arrowhead_height = unit(3, "mm"), arrowhead_width = unit(1, "mm")) + geom_gene_label() + geom_segment(aes(x=266,y=1.5,xend=13468,yend=1.5), size=0.2) + xlim(0,29903) +
  annotate("text", label="ORF1a", x=5000, y=1.41, size=3) + geom_segment(aes(x=13468,y=1.4,xend=21555,yend=1.4), size=0.2) + annotate("text", label="ORF1b", x=18000, y=1.31, size=3) +
  theme_genes() + ylab(NULL) + xlab(NULL) 
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.
((
  genome_fig_unlog<-plot_grid(gene_arrows, minor_prevalence_across_genome_unlog_labeled + theme(legend.position = "bottom"), nrow=2, rel_heights=c(0.25,1), axis="lr", align="hv")
))



ggsave("ggsave/genome_fig_unlog.pdf", plot = genome_fig_unlog, height = 5, width = 12)

Characteristics of highly recurrent minor variants

# What's the range of minor allele frequencies the highly recurrent minor variants are found at?
highly_shared_sites_top_ranked = highly_shared_sites_ranked %>% filter(rank <= 35)
highly_shared_sites = patient_var_30_for_rank %>% filter(paste0(gene,".",label) %in%
                                     paste0(highly_shared_sites_top_ranked$gene, ".", 
                                            highly_shared_sites_top_ranked$label)) %>%
          group_by(label, ntpos) %>% 
  summarize(ntpos, ntpos_count = n()) %>% distinct() %>% 
  arrange(-ntpos_count) %>% 
  filter(ntpos_count > (patient_var_30$MCoVNumber %>% unique %>% length)*0.01) %>% pull(ntpos)
`summarise()` has grouped output by 'label', 'ntpos'. You can override using the `.groups` argument.
((
  hss_maf<-patient_var_30 %>% filter(ntpos %in% highly_shared_sites) %>% 
    ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
    geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
    geom_boxplot(outlier.shape = NA, alpha =0.5) + 
    theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
    xlab("Nucleotide position") + ylab("Minor allele freq") + 
    scale_y_continuous(trans="log2", breaks = c(0.01*2^(0:5), 0.5))
  ))

ggsave("ggsave/hss_maf.pdf", width = 4, height = 1, plot = hss_maf)


((
  hss_maf_unlog<-patient_var_30 %>% filter(ntpos %in% highly_shared_sites) %>% 
    ggplot(aes(x = as.factor(ntpos), y = minorfreq)) + 
    geom_point(alpha = 0.2, position = position_jitter(width = 0.1)) + theme_bw() + 
    geom_boxplot(outlier.shape = NA, alpha = 0.5) + 
    theme(axis.text.x = element_text(angle=90)) + #geom_boxplot(outlier.alpha = 0) + 
    xlab("Nucleotide position") + ylab("Minor allele freq") #+ 
    #scale_y_continuous(trans="log2", breaks = c(0.01*2^(0:5), 0.5))
  ))
ggsave("ggsave/hss_maf_unlog.pdf", width = 4, height = 2, plot = hss_maf_unlog)

#How many different changes do you find at each recurrently-mutated position? How many such mutations are a reversion to the reference?
hss_info <- fread('hss_data2.csv', data.table = F)

((
  hss_plot = patient_var_30_for_rank %>% mutate(label_gene = paste0(gene, ": ", label)) %>%
    filter(ntpos %in% highly_shared_sites) %>% 
    group_by(ntpos, major, minor) %>% mutate(n=n(), median_frequency = median(minorfreq)) %>%     mutate(change=paste0(major,">",minor)) %>% 
    mutate(ref_reversion=if_else(minor==refnt,"yes","no")) %>% 
    mutate(median_MAF=if_else(median_frequency<0.02, 
                              "low (median <2% MAF)","high (median >=2% MAF)")) %>%
    select(change, n, ref_reversion, ntpos, label_gene, median_MAF) %>% distinct %>%
    ggplot(aes(x=change, y=n, color=ref_reversion)) + 
    geom_bar(stat="identity", aes(fill=median_MAF)) + 
    scale_color_manual(values=c("white","red")) + 
    scale_fill_manual(values=c("darkmagenta","steelblue")) + 
    facet_wrap(ntpos~label_gene, scales="free") + 
    theme_pubr() + theme(axis.text.x=element_text(angle=90))
))
Adding missing grouping variables: `major`, `minor`

ggsave('ggsave/hss_plot.pdf', plot = hss_plot, width = 11, height = 13)
ldm_vector = lineage_defining_mutations$nt_pos
heatmap_spectra_tmp = patient_var_30_for_rank %>% 
  mutate(label_gene = paste0(gene, ": ", label)) %>%
    filter(ntpos %in% highly_shared_sites) %>% 
    group_by(ntpos, major, minor) %>% mutate(n=n(), median_frequency = median(minorfreq)) %>%
  mutate(change=paste0(major,">",minor), 
         transition = ifelse(change %in% c("C>T","T>C","A>G","G>A"), 1, 0)) %>%
     mutate(ref_reversion=if_else(minor==refnt,1,0)) %>% ungroup() %>%
  select(change, n, ntpos, label_gene) %>% distinct %>% 
  group_by(ntpos) %>% mutate(ntpos_n = sum(n)) %>% ungroup() %>%
  mutate(n_prop = n/ntpos_n) %>% select(-n) %>% 
  mutate(ldm = as.factor(ifelse(ntpos %in% ldm_vector, 1, 0))) %>%
  mutate(label = paste0(label_gene, " - ", ntpos, " (", ntpos_n, ")"))


annotation_row_df = heatmap_spectra_tmp %>% select(label, ldm) %>% 
  distinct %>% as.data.frame() %>%
  column_to_rownames("label")
annotation_row_df
#%>%
heatmap_spectra = heatmap_spectra_tmp %>% select(-ldm) %>% spread(change, n_prop) %>% 
  arrange(-ntpos_n) %>% distinct() %>%  
  select(-c(ntpos, label_gene, ntpos_n)) %>% replace(.,is.na(.),0) %>%
  column_to_rownames("label")

annotation_col_df = heatmap_spectra_tmp %>% select(change) %>% distinct %>% 
  mutate(transversion = 
           as.factor(ifelse(!(change %in% c("C>T","T>C","A>G","G>A")), 
                            1, 0))) %>% 
  column_to_rownames("change")

maf = heatmap_spectra_tmp %>% select(ntpos, label) %>% distinct %>%
  left_join(patient_var_30 %>% select(ntpos, minorfreq)) %>% 
  select(label, minorfreq)
Joining, by = "ntpos"
maf_list = split(maf$minorfreq,maf$label)

row_ha = rowAnnotation(df = data.frame(
  ldm = annotation_row_df[rownames(heatmap_spectra),]), 
  col = list(ldm = c(`1`="grey", `0`="white")),
  MAF = anno_boxplot(maf_list, pch = 20, size = unit(0.5, "mm")))


heatmap_spectra_reorder = heatmap_spectra %>% select(c("A>G","G>A","C>T","T>C",
                                               "A>C", "C>A", "A>T", "T>A",
                                               "C>G", "G>C", "G>T", "T>G"))
col_ha = columnAnnotation(df = data.frame(
  transversion = annotation_col_df[colnames(heatmap_spectra_reorder),]), 
                          col = list(transversion = c(`1`="grey", `0`="white")))

heatmap_spectra_hss = Heatmap(heatmap_spectra_reorder,
                              name = "prop/site",
                              col = colorRampPalette(
                                c("white", "brown4"))(100),
                              show_row_dend = F, 
                              cluster_columns = F, left_annotation = row_ha,
                              rect_gp = gpar(col = "grey90", lwd = 1),
                              top_annotation = col_ha,
                              heatmap_legend_param = 
                                list(direction = "vertical")) 
Warning: The input is a data frame-like object, convert it to a matrix.Warning: Values in row annotation 'MAF' have a different order of names from the matrix
row names. It may lead to wrong conclusion of your data. Please double check.
pdf(qq("ggsave/heatmap_spectra_hss.pdf"), width = 6.5, height = 7)
draw(heatmap_spectra_hss, merge_legend = TRUE, 
     heatmap_legend_side = "right", 
    annotation_legend_side = "right")
dev.off()
null device 
          1 
heatmap_spectra_hss

# 
#           border_color = "grey90", colorRampPalette(c("white", "brown4"))(100),
#          treeheight_row = 0, treeheight_col = 10, annotation_col = annotation_col_df,
#          annotation_row = annotation_row_df, annotation_colors = annotation_colors)
# pacman::p_load(ComplexHeatmap)
         
#all minor variants that are found in at least 2% of high-coverage samples in Lythgoe et al https://www.science.org/doi/suppl/10.1126/science.abg0821/suppl_file/abg0821-lythgoe-sm.pdf
Warning message:
The closing backticks on line 240 ("```") in 03_recurrent_mutations_analysis.Rmd do not match the opening backticks " ```" on line 209. You are recommended to fix either the opening or closing delimiter of the code chunk to use exactly the same numbers of backticks and same level of indentation (or blockquote). 
lythgoe_hss<-c(29320, 25628, 25807, 20364, 357, 25627, 25532, 11083, 239, 238, 356, 16740, 20989, 19393, 15009, 21826, 19937, 26289,28253,25507,29862,11052,29864,25529,369,22453,13571,29538,21575,75,20993,19473,15474,635,1226,29747,24933,19210,13303,28936,26334,16887)

tonkin_hss<-c(11075L, 11083L, 11074L, 522L, 26780L, 1547L, 14408L, 28253L, 13914L, 26137L, 635L, 241L, 26785L, 683L, 23403L, 28881L, 13778L, 25521L, 14805L, 9491L, 11071L, 13780L, 21575L, 29242L, 9430L, 203L, 3037L, 686L, 3096L, 16375L, 16466L, 17167L, 23559L, 9438L, 21137L, 29051L, 23555L, 26333L, 9474L, 13571L, 16887L, 26787L, 28603L, 24213L, 11651L, 27925L, 514L, 26781L, 558L, 1912L, 9479L, 11073L, 12578L, 26144L, 26681L, 29241L)
intersect(lythgoe_hss, highly_shared_sites)
[1] 11083 28253
intersect(tonkin_hss, highly_shared_sites)
[1] 11083 28253 14805
homoplasic_site_list<-c(187L, 1059L, 2094L, 3037L, 3130L, 6990L, 8022L, 10323L, 10741L, 11074L, 11083L, 13408L, 14786L, 15324L, 19684L, 20148L, 21137L, 21575L, 24034L, 24378L, 25563L, 26144L, 26461L, 26681L, 28077L, 28826L, 28854L, 29700L)
intersect(homoplasic_site_list, highly_shared_sites)
[1] 11083 25563
ggsave("ggsave/gisaid_vs_hmh_plot_marginal.pdf", plot = gisaid_vs_hmh_marginal, width = 6, height = 5)
Warning: ggrepel: 15 unlabeled data points (too many overlaps). Consider increasing max.overlaps
# MUTATION SPECTRA ANALYSIS

# reproducibility analysis from RMD 01
plot_nonreproducible_spectra_heatmap = readRDS(file = "plot_nonreproducible_spectra_heatmap.rds")
plot_reproducible_spectra_heatmap = readRDS(file = "plot_reproducible_spectra_heatmap.rds")

hmap<-table(patient_var_30$major[patient_var_30$major!=""], patient_var_30$minor[patient_var_30$minor!=""]) %>% data.frame() %>%
  ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + geom_tile(colour = "black") +
  scale_fill_gradient(low = "white",
                      high = "darkblue") +
  theme_minimal() +   labs(fill = "Number",
       x = "Consensus allele",
       y = "Minor allele", title = "Post-sample filter (Ct, n_var)") #Most frequently C>T mutations

# Now beecause some peaks are really prevalent like the twin peaks at 29187/8, 
# it's important to not factor that in too much. So let's just assign those mutations
# to equate to the median number a mutation appears which is 1.

mutation_spectra = patient_var_30 %>% unite(col = "spectra_mutation", 
                                            major, ntpos, minor, remove = FALSE)
mutation_spectra_counts = mutation_spectra %>% count(spectra_mutation)

mutation_spectra_counts %>% ggplot(aes(y=n)) + geom_boxplot() + 
  scale_y_continuous(trans = "log1p")

mutation_spectra_counts$n %>% quantile() # median is 1

mutation_spectra_unique = mutation_spectra %>% 
  select(major, minor, spectra_mutation) %>% unique()

hmap_unique <-table(mutation_spectra_unique$major[mutation_spectra_unique$major!=""], mutation_spectra_unique$minor[mutation_spectra_unique$minor!=""]) %>% data.frame() %>%
  ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + geom_tile(colour = "black") + # grid color
  scale_fill_gradient(limits = c(0,0.4), low = "white",
                      high = "darkblue") +
  theme_minimal() +   labs(fill = "Fraction",
       x = "Consensus allele",
       y = "Minor allele", title="Unique minor variants")

rescale_fill = function(hmap_unique) {
  hmap_unique_rescaled = hmap_unique + 
    scale_fill_gradient(limits = c(0,0.4), low = "white",
                      high = "darkblue") +
    geom_label(fill = "white", alpha = 0.3, aes(x = Var1, y = Var2, label = round(Freq/sum(Freq), digits = 2)))
  return(hmap_unique_rescaled)
}

((
  rep_nucleotides = ggarrange(rescale_fill(plot_nonreproducible_spectra_heatmap), 
                              rescale_fill(plot_reproducible_spectra_heatmap), 
                              rescale_fill(hmap), 
                              rescale_fill(hmap_unique), common.legend = T)
))
rep_nucleotides

ggsave("ggsave/heatmap_spectra_replicate_variants.pdf", rep_nucleotides, height = 6, width = 6)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKV2hhdCBhcmUgdGhlIG1vc3QgZnJlcXVlbnQgbWlub3IgdmFyaWFudHMgaW4gdGhlIGhpZ2gtY29uZmlkZW5jZSBzYW1wbGVzPwpgYGB7cn0Kc291cmNlKCIuL3NjcmlwdHMvc3RhcnR1cC5SIikKCnBhdGllbnRfdmFyXzMwID0gcmVhZF9mZWF0aGVyKCJwcm9jZXNzaW5nL3BhdGllbnRfdmFyXzMwLmFycm93IikKbWFmX2hpc3RvZ3JhbSA9IHBhdGllbnRfdmFyXzMwICU+JSBnZ3Bsb3QoYWVzKG1pbm9yZnJlcSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxKSArIHRoZW1lX3B1YnIoKQpxdWFudGlsZShwYXRpZW50X3Zhcl8zMCRtaW5vcmZyZXEsIHByb2JzID0gYyguMjUsLjUsLjc1KSwgbmEucm0gPSBUKQpnZ3NhdmUoImdnc2F2ZS9tYWZfaGlzdG9ncmFtLnBkZiIsIG1hZl9oaXN0b2dyYW0sIHdpZHRoID0gMywgaGVpZ2h0ID0gMykKCnBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rID0gcGF0aWVudF92YXJfMzAgJT4lIGRyb3BfbmEoZ2VuZSkgJT4lIGZpbHRlcihnZW5lICE9IiIpICU+JQogIG11dGF0ZShsYWJlbCA9IHBhc3RlMChyZWZfc3ltLCBhYXBvcyksIAogICAgICAgICByZWZudCA9IHN0cl9zdWIocmVmX2NvZG9uLCBzdGFydCA9IGNvZG9uX3BvcywgZW5kID0gY29kb25fcG9zKSkKYnAgPSBjKCJBIiwgIlQiLCAiQyIsICJHIikKbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMgPSBmcmVhZCgiMjAyMjAxMDMtVFJBQ0UtTGluZWFnZURlZmluaXRpb25zLXY5LjEudHh0IiwgZGF0YS50YWJsZSA9IEYpICU+JQogIGZpbHRlcihudF9yZWYgJWluJSBicCAmIAogICAgICAgICAgIG50X2FsdCAlaW4lIGJwICYgCiAgICAgICAgICAgdmFyaWF0aW9uX3R5cGUgPT0gIlNOUCIpICU+JSBzZWxlY3QobnRfcG9zLCBudF9yZWYsIG50X2FsdCkKbGRtX21hcCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSAKICBtdXRhdGUobGRtICA9IGlmZWxzZShudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywgVFJVRSwgRkFMU0UpKSAlPiUgCiAgc2VsZWN0KGdlbmUsIGxhYmVsLCBsZG0pICU+JSBkaXN0aW5jdCAlPiUgZ3JvdXBfYnkoZ2VuZSwgbGFiZWwpICU+JSBhcnJhbmdlKC1sZG0pICU+JQogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEpCiAgCgpoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSBkcm9wX25hKGdlbmUpICU+JSBmaWx0ZXIoZ2VuZSAhPSIiKSAlPiUKICBtdXRhdGUobGFiZWwgPSBwYXN0ZTAocmVmX3N5bSwgYWFwb3MpLCAKICAgICAgICAgcmVmbnQgPSBzdHJfc3ViKHJlZl9jb2Rvbiwgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcykpICU+JQogIGdyb3VwX2J5KG1jb3ZfaWQsIGdlbmUsIGxhYmVsKSAlPiUKICB0YWxseSgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgdW5ncm91cCAlPiUgZ3JvdXBfYnkoZ2VuZSwgbGFiZWwpICU+JSAKICBzdW1tYXJpemUobGFiZWxfY291bnQgPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lIGFycmFuZ2UoLWxhYmVsX2NvdW50KSAlPiUgbXV0YXRlKHJhbmsgPSAxOm5yb3coLikpICU+JQogIGxlZnRfam9pbihsZG1fbWFwKSAlPiUgdW5pcXVlKCkKCiMgaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWRfNTAgPSBoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZCAlPiUgZmlsdGVyKHJhbmsgPD0gMjUpCiMgCiMgKCgKIyAgIGhzc19tYWZfNTA8LXBhdGllbnRfdmFyXzMwICU+JSBmaWx0ZXIocGFzdGUwKGdlbmUsIGFhcG9zKSAlaW4lIHBhc3RlMChoaWdobHlfc2hhcmVkX3NpdGVzX3JhbmtlZF81MCRnZW5lLCBwYXJzZV9udW1iZXIoaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWRfNTAkbGFiZWwpKSkgJT4lIAojICAgICBnZ3Bsb3QoYWVzKHggPSBhcy5mYWN0b3IobnRwb3MpLCB5ID0gbWlub3JmcmVxKSkgKyAKIyAgICAgI2dlb21fcG9pbnQoYWxwaGEgPSAwLjIsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMC4xKSkgKyB0aGVtZV9idygpICsgCiMgICAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0wLjUpICsgdGhlbWVfYncoKSArCiMgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkgKyAjZ2VvbV9ib3hwbG90KG91dGxpZXIuYWxwaGEgPSAwKSArIAojICAgICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKyB5bGFiKCJNaW5vciBhbGxlbGUgZnJlcSIpICkpCiMgCiMgZ2dzYXZlKCJnZ3NhdmUvaHNzX21hZl81MC5wZGYiLCBoc3NfbWFmXzUwLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCgoKIyU+JSAKICMgbGVmdF9qb2luKHBhdGllbnRfdmFyXzMwICU+JSBzZWxlY3QobnRwb3MsIGdlbmUsIHJlZl9zeW0sIGFhcG9zLCByZWZfY29kb24sIGNvZG9uX3BvcykgJT4lIGRpc3RpbmN0KQoKIyAoKAojICAgaGlnaGx5X3NoYXJlZF9zaXRlczwtIHBhdGllbnRfdmFyXzMwICU+JSBncm91cF9ieShudHBvcykgJT4lIHRhbGx5KCkgJT4lIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAojICAgICAgICBkcm9wX25hKG50cG9zKSAlPiUgc2xpY2VfbWF4KG4sIG4gPSAzNSkgJT4lIHB1bGwobnRwb3MpICU+JSBhcy5udW1lcmljKCkKIyApKQoKCnNhbXBsZV9uID0gbGVuZ3RoKHVuaXF1ZShwYXRpZW50X3Zhcl8zMCRtY292X2lkKSkKI2ZvciAodGhpc19nZW5lIGluIGdlbmVfbGltaXRzJGdlbmVfaWQpIHsKICBwbG90X3JhbmtzID0gaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWQgJT4lIGZpbHRlcihyYW5rIDw9IDM1KSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHJhbmssIGxhYmVsX2NvdW50LCBsYWJlbCA9IGxhYmVsKSkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IGhpZ2hseV9zaGFyZWRfc2l0ZXNfcmFua2VkICU+JSAKICAgICAgICAgICAgICBzZWxlY3QoIWdlbmUpICU+JSBmaWx0ZXIocmFuayA8PSAzNSksIGFlcyhyYW5rLCBsYWJlbF9jb3VudCksIGNvbG9yID0gImdyZXkiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzIiLCBicmVha3MgPSAyXnNlcSgwLDEyLDEpLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uL3NhbXBsZV9uLCBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IDJec2VxKDAsOCwxKS8xMDApKSArIHRoZW1lX3B1YnIoKSArCiAgZ2VvbV9wb2ludChhZXMocmFuaywgbGFiZWxfY291bnQpLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBsYWJlbCwgY29sb3IgPSBsZG0pLCB5bGltID0gYyg2LDExKSwgeGxpbSA9IGMoTkEsIE5BKSwgYW5nbGUgPSA5MCwKICAgICAgICAgICAgICAgICAgc2VnbWVudC5zaXplID0gMC42LCBzZWdtZW50LmN1cnZhdHVyZSA9IC0xZS0yMCwgc2VnbWVudC5saW5ldHlwZSA9IDMsCiAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZikgKyBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygic2FsbW9uIiwgImdyZXkiKSkgKwogICAgZmFjZXRfd3JhcCh+Z2VuZSkKICAKICBwbG90X3JhbmtzCiN9Cmdnc2F2ZSgiZ2dzYXZlL3Bsb3RfcmFua3MucGRmIiwgcGxvdF9yYW5rcywgaGVpZ2h0ID0gNS41LCB3aWR0aCA9IDcpCmBgYAoKCgpgYGB7cn0KIyBBY3Jvc3MgZ2Vub21lCgoKbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMKCnBsb3RfZGF0YV9MRE1fcHJvcCA9IHBhdGllbnRfdmFyXzMwICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgZHJvcF9uYShudHBvcykgJT4lIAogIHN1bW1hcml6ZShpU05WX2NvdW50ID0gbigpLCBpU05WID0gcGFzdGUwKG50cG9zLCBjb2xsYXBzZSA9ICIsIiksIAogICAgICAgICAgICBpU05WX0xETV9jb3VudCA9IGxlbmd0aChudHBvc1tudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3Bvc10pLAogICAgICAgICAgICBpU05WX0xETSA9IHBhc3RlMChudHBvc1tudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3Bvc10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gIiwiKSwgcHJvcCA9IGlTTlZfTERNX2NvdW50L2lTTlZfY291bnQpCgpwbG90X2RhdGFfTERNX3Byb3AgJT4lIGdncGxvdChhZXMoYXMuZmFjdG9yKGlTTlZfY291bnQpLCBwcm9wKSkgKyBnZW9tX3Zpb2xpbihkcmF3X3F1YW50aWxlcz1jKDAuNSkpCgpgYGAKYGBge3J9CnBhdGllbnRfdmFyXzMwX3JldmVyc2lvbnMgPSBwYXRpZW50X3Zhcl8zMCAlPiUgbXV0YXRlKHJldmVyc2lvbiA9IG1pbm9yID09IHN0cl9zdWIocmVmX2NvZG9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gY29kb25fcG9zLCBlbmQgPSBjb2Rvbl9wb3MpKSAlPiUgZHJvcF9uYShyZXZlcnNpb24pCgojIEhvdyBtYW55IG9mIG91ciBhbGxlbGVzIHdlcmUgcmV2ZXJzaW9ucz8KcGF0aWVudF92YXJfMzBfcmV2ZXJzaW9ucyAlPiUgc3VtbWFyaXplKHByb3BvcnRpb25fcmV2ZXJzaW9uID0gc3VtKHJldmVyc2lvbj09VCkvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cocGF0aWVudF92YXJfMzApKQoKIyBIb3cgbWFueSBvZiBvdXIgYWxsZWxlcyB0aGF0IGFyZSByZXZlcnNpb25zIGFyZSBhdCBMRE0gc2l0ZXM/CnBhdGllbnRfdmFyXzMwX3JldmVyc2lvbnMgJT4lIG11dGF0ZShsZG0gPSBpZmVsc2UobnRwb3MgJWluJSBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9wb3MsMSwwKSkgJT4lIAogIHN1bW1hcml6ZShwcm9wb3J0aW9uX3JldmVyc2lvbiA9IHN1bShsZG0gPT0gMSAmIHJldmVyc2lvbiA9PSBUKS9zdW0ocmV2ZXJzaW9uPT1UKSkKCiMgb2JzY3VyZSB0aGUgY29uc2Vuc3VzIGluIHRoZSBWQ0YKcHJvYmxlbV9zaXRlc19nbG9iYWwgPSBmcmVhZCgicHJvYmxlbWF0aWNfc2l0ZXNfc2Fyc0NvdjJfdjgtMjAyMTEwMjcudmNmIiwgc2tpcCA9IDg4KSAlPiUKICBmaWx0ZXIoRklMVEVSICE9ICJtYXNrIikgJT4lCiAgZmlsdGVyKCFncmVwbCgnc2luZ2xlX3NyY3xuYW5vcG9yZScsIElORk8pKSAlPiUgcHVsbChQT1MpCnByb2JsZW1fc2l0ZXNfaG91c3RvbiA9IGZyZWFkKCJwcm9ibGVtYXRpY19zaXRlc19zYXJzQ292Ml92OC0yMDIxMTAyNy52Y2YiLCBza2lwID0gODgpICU+JQogIGZpbHRlcihncmVwbCgnSG91c3RvbicsIElORk8pKSAlPiUgcHVsbChQT1MpCnByb2JsZW1fc2l0ZXMgPSB1bmlxdWUoYyhwcm9ibGVtX3NpdGVzX2dsb2JhbCwgcHJvYmxlbV9zaXRlc19ob3VzdG9uKSkKcHJvYmxlbV9zaXRlcwoKIyBVTkNPTU1FTlQgQkVMT1cgSUYgTkVDRVNTQVJZIFRPIFJFR0VORVJBVEUgREFUQQojIGNvbnNlbnN1cyA8LWZyZWFkKCJjb25zZW5zdXNfbWlub3JfY2hhbmdlc18yMDIyMDcxMy5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lIGZpbHRlcighbnRwb3MgJWluJSBwcm9ibGVtX3NpdGVzKSAlPiUgZmlsdGVyKCFudHBvcyAlaW4lIGMoMToyNjUpKSAlPiUgZmlsdGVyKCFudHBvcz4yOTY3NCkKIyAKIyAKIyAKIyBjb25zZW5zdXMgCiMgCiMgIwojIGNvbnNlbnN1c19jb3VudCA9IGNvbnNlbnN1cyAlPiUgCiMgICBtdXRhdGUoTUNvVk51bWJlciA9IG1jb3ZfcmVmb3JtYXQobmFtZSkpICU+JSAKIyAgIHNlbGVjdChNQ29WTnVtYmVyLCBtYWpvciwgbnRwb3MsIHJlZm50KSAlPiUgCiMgICBmaWx0ZXIobWFqb3IgIT0gcmVmbnQpICU+JSAKIyAgIHVuaXF1ZSgpICU+JQojICAgZ3JvdXBfYnkobnRwb3MpICU+JQojICAgc3VtbWFyaXplKE1Db1ZOdW1iZXIgPSB1bmlxdWUoTUNvVk51bWJlcikpIAojIAojIHJ1bnMgPSBmcmVhZCgic2FtcGxlX2RhdGVfYW5kX3J1bi5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lCiMgICAgIG11dGF0ZShNQ29WTnVtYmVyID0gbWNvdl9yZWZvcm1hdChtY292X2lkKSkKIyAKIyBjb25zZW5zdXNfcnVucyA9IGNvbnNlbnN1c19jb3VudCAlPiUgbGVmdF9qb2luKHJ1bnMpICU+JSBkcm9wX25hKCkgJT4lCiMgICBzZWxlY3QobnRwb3MsIE1Db1ZOdW1iZXJfcG9zc2libGVfY29udGFtaW5hbnQgPSBNQ29WTnVtYmVyLCBydW5fY29uc2Vuc3VzID0gcnVuX2dyb3VwKSAjaGFzIGVhY2ggb2YgdGhlIGNvbnNlbnN1cyBtdXRhdGlvbnMgd2l0aCB0aGUgTUNPVgojIAojICMgdW5jb21tZW50IGJlbG93IGlmIG5lY2Vzc2FyeQojICNwYXRpZW50X3Zhcl8zMF9jb250YW1pbmF0ZWQgPSBwYXRpZW50X3Zhcl8zMCAlPiUgbGVmdF9qb2luKGNvbnNlbnN1c19ydW5zKSAjIGludGVuc2l2ZQojICN3cml0ZV9mZWF0aGVyKHBhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZCwgInByb2Nlc3NpbmcvcGF0aWVudF92YXJfMzBfY29udGFtaW5hdGVkLmFycm93IikKIyAKcGF0aWVudF92YXJfMzBfY29udGFtaW5hdGVkID0gcmVhZF9mZWF0aGVyKCJwcm9jZXNzaW5nL3BhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZC5hcnJvdyIpCmNvbnRhbWluYXRlZF9kZiA9IHBhdGllbnRfdmFyXzMwX2NvbnRhbWluYXRlZCAlPiUgbXV0YXRlKHJlZl9udCA9IHN0cl9zdWIocmVmX2NvZG9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcykpICU+JQogIHNlbGVjdChNQ29WTnVtYmVyLCBydW5fZ3JvdXAsIG50cG9zLCByZWZfbnQsIG1ham9yLCBtaW5vciwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCwgcnVuX2NvbnNlbnN1cykKCmNvbnRhbWluYXRlZF9kZl90YWxsaWVkID0gY29udGFtaW5hdGVkX2RmICU+JQogIGZpbHRlcihydW5fZ3JvdXAgPT0gcnVuX2NvbnNlbnN1cykgJT4lCiAgZ3JvdXBfYnkoTUNvVk51bWJlcikgJT4lCiAgc3VtbWFyaXplKG5fdmFyX2NvbnRhbSA9IGxlbmd0aCh1bmlxdWUobnRwb3MpKSwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCkgJT4lCiAgZ3JvdXBfYnkoTUNvVk51bWJlciwgTUNvVk51bWJlcl9wb3NzaWJsZV9jb250YW1pbmFudCkgJT4lCiAgc3VtbWFyaXplKG5fdmFyX2NvbnRhbSwgc2luZ2xlX3NhbXBsZSA9IG4oKSwgcHJvcF9zaW5nbGVfc2FtcGxlID0gc2luZ2xlX3NhbXBsZSAvIG5fdmFyX2NvbnRhbSkKCmNvbnRhbWluYXRlZF9kZl90YWxsaWVkX3RvcCA9IGNvbnRhbWluYXRlZF9kZl90YWxsaWVkICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgdG9wX24obj0xKSAlPiUKICBmaWx0ZXIocm93X251bWJlcigpPT0xKQojTm90ZSBwcm9wX3NpbmdsZV9zYW1wbGUgaXMgc2luZ2xlX3NhbXBsZSAvIG5fdmFyX2NvbnRhbSAocHJvcG9ydGlvbiBvZiBudW1iZXIgb2YgbWlub3IgdmFyaWFudHMgdGhhdCByZXNlbWVtYmxlIGNvbnNlbnN1cyBpbiBhbm90aGVyIHNhbXBsZSAvIG51bWJlciBvZiBtaW5vciB2YXJpYW50cyB0aGF0IHJlc2VtYmxlIGFueSBjb25zZW5zdXMgaW4gdGhlIHJ1bikKIyBwcm9wIHNpbmdsZSBjb250YW0gaXMgdGhlIHNhbWUgYXMgYWJvdmUgYnV0IHRoZSBkZW5vbSBpcyBvdXQgb2Ygbl92YXIKcGF0aWVudF9jb3VudHNfMzAgPSByZWFkX2ZlYXRoZXIoInByb2Nlc3NpbmcvcGF0aWVudF9jb3VudHNfMzAuYXJyb3ciKQpwYXRpZW50X2NvdW50c18zMF9hbm5vID0gcGF0aWVudF9jb3VudHNfMzAgJT4lIGxlZnRfam9pbihjb250YW1pbmF0ZWRfZGZfdGFsbGllZF90b3ApICU+JQogIG11dGF0ZShydW5fbnVtID0gYXMubnVtZXJpYyhzdHJfcmVwbGFjZShydW5fZ3JvdXAsICJSdW5fIiwgIiIpKSkgJT4lCiAgcmVwbGFjZShpcy5uYSguKSwwKQoKIyBQbG90OiBuX3ZhciB4IHByb2IgdGhhdCBpdCdzIGZyb20gYSBzaW5nbGUgc291cmNlCnBsb3RfY29udGFtID0gcGF0aWVudF9jb3VudHNfMzBfYW5ubyAlPiUgbXV0YXRlKHByb3BfY29udGFtID0gbl92YXJfY29udGFtL25fdmFyLCBwcm9wX3NpbmdsZV9jb250YW0gPSBzaW5nbGVfc2FtcGxlL25fdmFyKSAKCnBsb3RfY29udGFtICU+JSBzZWxlY3Qobl92YXIsIGFkbWl0dGVkX2hvc3BpdGFsLCBwcm9wX2NvbnRhbSwgcHJvcF9zaW5nbGVfY29udGFtKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHM9IGMocHJvcF9jb250YW0sIHByb3Bfc2luZ2xlX2NvbnRhbSksIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAicHJvcCIpICAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhZG1pdHRlZF9ob3NwaXRhbCwgeSA9IHByb3AsIAogICAgICAgICAgICAgZmlsbCA9IHR5cGUpKSArIAogIGdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LDAuNSwwLjc1KSkKCm1lZGlhbl9jb250YW1fY29udGFtID0gcXVhbnRpbGUocGxvdF9jb250YW0gJT4lIGZpbHRlcihuX3ZhciA+IDApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1bGwocHJvcF9jb250YW0pLCBwcm9icyA9IGMoMC41KSkKcHJpbnQobWVkaWFuX2NvbnRhbV9jb250YW0pCnBsb3RfY29udGFtX2NvbnRhbSA9IHBsb3RfY29udGFtICU+JSAKICBzZWxlY3Qobl92YXIsIGFkbWl0dGVkX2hvc3BpdGFsLCBwcm9wX2NvbnRhbSwgcHJvcF9zaW5nbGVfY29udGFtKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbl92YXIsIHkgPSBwcm9wX2NvbnRhbSwgCiAgICAgICAgICAgICBmaWxsID0gYWRtaXR0ZWRfaG9zcGl0YWwsIGNvbG9yID0gYWRtaXR0ZWRfaG9zcGl0YWwpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjAyKSArIGdlb21fc21vb3RoKCkgKyB0aGVtZV9wdWJyKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lZGlhbl9jb250YW1fY29udGFtLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKcGxvdF9jb250YW1fY29udGFtID0gZ2dNYXJnaW5hbChwbG90X2NvbnRhbV9jb250YW0sIGdyb3VwQ29sb3VyID0gVCwgZ3JvdXBGaWxsID0gVCwgdHlwZSA9ICJ2aW9saW4iLAogICAgICAgICAgIGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LCAwLjUsIDAuNzUpKQoKbWVkaWFuX3NpbmdsZV9jb250YW0gPSBxdWFudGlsZShwbG90X2NvbnRhbSAlPiUgZmlsdGVyKG5fdmFyID4gMCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVsbChwcm9wX3NpbmdsZV9jb250YW0pLCBwcm9icyA9IGMoMC41KSkKcHJpbnQobWVkaWFuX3NpbmdsZV9jb250YW0pCnBsb3RfY29udGFtX3NpbmdsZV9jb250YW0gPSBwbG90X2NvbnRhbSAlPiUgCiAgc2VsZWN0KG5fdmFyLCBhZG1pdHRlZF9ob3NwaXRhbCwgcHJvcF9jb250YW0sIHByb3Bfc2luZ2xlX2NvbnRhbSkgJT4lIAogIGdncGxvdChhZXMoeCA9IG5fdmFyLCB5ID0gcHJvcF9zaW5nbGVfY29udGFtLCAKICAgICAgICAgICAgIGZpbGwgPSBhZG1pdHRlZF9ob3NwaXRhbCwgY29sb3IgPSBhZG1pdHRlZF9ob3NwaXRhbCkpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDIpICsgZ2VvbV9zbW9vdGgoKSArIHRoZW1lX3B1YnIoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lZGlhbl9zaW5nbGVfY29udGFtLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKcGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSA9IGdnTWFyZ2luYWwocGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwQ29sb3VyID0gVCwgZ3JvdXBGaWxsID0gVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAidmlvbGluIiwKICAgICAgICAgICBkcmF3X3F1YW50aWxlcyA9IGMoMC4yNSwgMC41LCAwLjc1KSkKCnBsb3RfY29udGFtX2FycmFuZ2VkID0gZ2dhcnJhbmdlKHBsb3RfY29udGFtX2NvbnRhbSwgcGxvdF9jb250YW1fc2luZ2xlX2NvbnRhbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ24gPSAidiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9ICJBVVRPIikKcGxvdF9jb250YW1fYXJyYW5nZWQKZ2dzYXZlKCJnZ3NhdmUvcGxvdF9jb250YW1fYXJyYW5nZWQucGRmIiwgcGxvdF9jb250YW1fYXJyYW5nZWQsIGhlaWdodCA9IDMsIHdpZHRoID0gNikKYGBgCgoKYGBge3J9CiNjb25zZW5zdXNfc2l0ZXNfbG93Y3QgJT4lIGZpbHRlcihyZWZudCA9PSBtYWpvcikKcGF0aWVudF9jb3VudHNfMzAgPSByZWFkX2ZlYXRoZXIoInByb2Nlc3NpbmcvcGF0aWVudF9jb3VudHNfMzAuYXJyb3ciKQoKCiMgY3JpdGVyaWEgdG8gY291bnQgdGhlIG11dGF0aW9uCiMgY29uc2Vuc3VzID0gaWYgbnRwb3MgbWF0Y2hlcyBpbiB0aGUgbGlzdCBhYm92ZSwgdGhlbiAKIyB0aGUgbWlub3Igd2lsbCBhbHNvIG1hdGNoIHRoZSBudF9yZWYgKGkuZS4gcmV2ZXJzaW9uKSBvciB0aGUgbnRfYWx0CgoKbGRtID0gYyhwYXN0ZTAobGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMkbnRfYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9yZWYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3JlZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lYWdlX2RlZmluaW5nX211dGF0aW9ucyRudF9wb3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZWFnZV9kZWZpbmluZ19tdXRhdGlvbnMkbnRfYWx0KSkKICAgICAgICAKbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhID0gcGF0aWVudF92YXJfMzAgJT4lICNsZWZ0X2pvaW4oY29uc2Vuc3VzKSAlPiUgCiAgICBtdXRhdGUocmVmX250ID0gc3RyX3N1YihyZWZfY29kb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSBjb2Rvbl9wb3MsIGVuZCA9IGNvZG9uX3BvcyksCiAgICAgIHJlZl9tdXRhdGlvbiA9IHBhc3RlMChyZWZfbnQsIG50cG9zLCBtaW5vciksCiAgICAgIG11dGF0aW9uID0gcGFzdGUwKG1ham9yLCBudHBvcywgbWlub3IpLCBjb25zZW5zdXMgPSAKICAgICAgICAgICAgIGlmZWxzZShudHBvcyAlaW4lIGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcywgCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKChtdXRhdGlvbiAlaW4lIGxkbSkgfCAocmVmX211dGF0aW9uICVpbiUgbGRtKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSwgRkFMU0UpLCAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICBGQUxTRSkpICU+JSAjZmlsdGVyKGNvbnNlbnN1cyA9PSBGQUxTRSkgJT4lCiAgZ3JvdXBfYnkobnRwb3MsIGNvbnNlbnN1cykgJT4lIAogIHN1bW1hcml6ZShjb25zZW5zdXMgPSBjb25zZW5zdXMsIG4gPSBuKCkpICU+JQogIHVuaXF1ZSAlPiUgZHJvcF9uYSAlPiUgdW5ncm91cCAlPiUgYXJyYW5nZSgtbikgJT4lCiAgbXV0YXRlKHJhbmsgPSAxOm5yb3coLikpCgptaW5vcl9wcmV2YWxlbmNlX2Fjcm9zc19nZW5vbWVfdW5sb2cgPC0gbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhICAlPiUKICAgIGdncGxvdChhZXMoeCA9IG50cG9zLCB5ID0gbiwgZmlsbCA9IGNvbnNlbnN1cywgY29sb3IgPSBjb25zZW5zdXMpKSArIAogICAgIyBsYWJlbCB5b3VyIGRhdGEgdG9vIGZvciB0aGUgU0FMTU9OCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygic2FsbW9uIiwiZ3JleSIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsImdyZXkiKSkgKwogICAgCiAgICAgIGdlb21fcG9pbnQoIGFlcyh4ID0gbnRwb3MsIHk9IG4pLCBzaGFwZSA9ICIiKSArCiAgICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsImJsYWNrIikpICsgCiAgdGhlbWVfYncoKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG5yb3cocGF0aWVudF9jb3VudHNfMzApKjAuMDEsIGxpbmV0eXBlPSJkb3R0ZWQiKSArIAogIHhsYWIoIk51Y2xlb3RpZGUgcG9zaXRpb24iKSArIHlsYWIoIk5vLiBzYW1wbGVzIHcvbWlub3IgdmFyaWFudCBhdCBzaXRlIikgKyAKICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49Mjc4OTQsIHhtYXg9MjgyOTUsIHltaW49MCwgeW1heD1JbmYsIGFscGhhPTAuMiwgZmlsbD0iIzg1RDRFMyIpICsgCiAgYW5ub3RhdGUoInJlY3QiLCB4bWluPTI4Mjc0LCB4bWF4PTI5NTMzLCB5bWluPTAsIHltYXg9SW5mLCBhbHBoYT0wLjIsIGZpbGw9IiNGNEI1QkQiKSArIAogIGFubm90YXRlKCJyZWN0IiwgeG1pbj0yMTU2MywgeG1heD0yNTM4NCwgeW1pbj0wLCB5bWF4PUluZiwgYWxwaGE9MC4yLCBmaWxsPSIjRkFENzdCIikgKyAgeGxpbSgwLDI5OTAzKQoKbWlub3JfcHJldmFsZW5jZV9hY3Jvc3NfZ2Vub21lX3VubG9nCgptaW5vcl9wcmV2YWxlbmNlX2Fjcm9zc19nZW5vbWVfdW5sb2dfbGFiZWxlZCA9IAogIG1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZyArIAogIGdlb21fdGV4dF9yZXBlbChtYXgub3ZlcmxhcHMgPSBJbmYsIHlsaW0gID0gYyg1MDAsTkEpLCBzaXplID0gMywgYW5nbGUgPSA5MCwgCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQubGluZXR5cGUgPSAzLCBzZWdtZW50LnNpemUgPSAwLjYsIAogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0xZS0yMCwgCiAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjAxNSwgIm5wYyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImNsb3NlZCIpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhICU+JQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihyYW5rIDwgNTApLAogICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbnRwb3MsIHkgPSBuLCBsYWJlbCA9IG50cG9zLCBjb2xvciA9IGNvbnNlbnN1cywgZmlsbCA9IGNvbnNlbnN1cykpCm1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZ19sYWJlbGVkCgpnZW5lcyA8LSBmcmVhZCgibnRwb3NfZ2VuZV91cGRhdGUuY3N2IiwgZGF0YS50YWJsZSA9IEYpCgpnZW5lX2xpbWl0czwtIGdlbmVzICU+JSBncm91cF9ieShnZW5lX2lkKSAlPiUgc3VtbWFyaXNlKHN0YXJ0PW1pbihudHBvcyksIGVuZD1tYXgobnRwb3MpKSAlPiUgZmlsdGVyKGdlbmVfaWQhPSIiKSAlPiUgbXV0YXRlKG1vbGVjdWxlPSIiKQoKZ2VuZV9hcnJvd3M8LWdncGxvdChnZW5lX2xpbWl0cywgYWVzKHhtaW4gPSBzdGFydCwgeG1heCA9IGVuZCwgeT1tb2xlY3VsZSwgbGFiZWwgPSBnZW5lX2lkKSkgKwogIGdlb21fZ2VuZV9hcnJvdyhhcnJvd2hlYWRfaGVpZ2h0ID0gdW5pdCgzLCAibW0iKSwgYXJyb3doZWFkX3dpZHRoID0gdW5pdCgxLCAibW0iKSkgKyBnZW9tX2dlbmVfbGFiZWwoKSArIGdlb21fc2VnbWVudChhZXMoeD0yNjYseT0xLjUseGVuZD0xMzQ2OCx5ZW5kPTEuNSksIHNpemU9MC4yKSArIHhsaW0oMCwyOTkwMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFhIiwgeD01MDAwLCB5PTEuNDEsIHNpemU9MykgKyBnZW9tX3NlZ21lbnQoYWVzKHg9MTM0NjgseT0xLjQseGVuZD0yMTU1NSx5ZW5kPTEuNCksIHNpemU9MC4yKSArIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik9SRjFiIiwgeD0xODAwMCwgeT0xLjMxLCBzaXplPTMpICsKICB0aGVtZV9nZW5lcygpICsgeWxhYihOVUxMKSArIHhsYWIoTlVMTCkgCgoKKCgKICBnZW5vbWVfZmlnX3VubG9nPC1wbG90X2dyaWQoZ2VuZV9hcnJvd3MsIG1pbm9yX3ByZXZhbGVuY2VfYWNyb3NzX2dlbm9tZV91bmxvZ19sYWJlbGVkICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpLCBucm93PTIsIHJlbF9oZWlnaHRzPWMoMC4yNSwxKSwgYXhpcz0ibHIiLCBhbGlnbj0iaHYiKQopKQoKCgpnZ3NhdmUoImdnc2F2ZS9nZW5vbWVfZmlnX3VubG9nLnBkZiIsIHBsb3QgPSBnZW5vbWVfZmlnX3VubG9nLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDEyKQpgYGAKCiMjIENoYXJhY3RlcmlzdGljcyBvZiBoaWdobHkgcmVjdXJyZW50IG1pbm9yIHZhcmlhbnRzCmBgYHtyfQojIFdoYXQncyB0aGUgcmFuZ2Ugb2YgbWlub3IgYWxsZWxlIGZyZXF1ZW5jaWVzIHRoZSBoaWdobHkgcmVjdXJyZW50IG1pbm9yIHZhcmlhbnRzIGFyZSBmb3VuZCBhdD8KaGlnaGx5X3NoYXJlZF9zaXRlc190b3BfcmFua2VkID0gaGlnaGx5X3NoYXJlZF9zaXRlc19yYW5rZWQgJT4lIGZpbHRlcihyYW5rIDw9IDM1KQpoaWdobHlfc2hhcmVkX3NpdGVzID0gcGF0aWVudF92YXJfMzBfZm9yX3JhbmsgJT4lIGZpbHRlcihwYXN0ZTAoZ2VuZSwiLiIsbGFiZWwpICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChoaWdobHlfc2hhcmVkX3NpdGVzX3RvcF9yYW5rZWQkZ2VuZSwgIi4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdobHlfc2hhcmVkX3NpdGVzX3RvcF9yYW5rZWQkbGFiZWwpKSAlPiUKICAgICAgICAgIGdyb3VwX2J5KGxhYmVsLCBudHBvcykgJT4lIAogIHN1bW1hcml6ZShudHBvcywgbnRwb3NfY291bnQgPSBuKCkpICU+JSBkaXN0aW5jdCgpICU+JSAKICBhcnJhbmdlKC1udHBvc19jb3VudCkgJT4lIAogIGZpbHRlcihudHBvc19jb3VudCA+IChwYXRpZW50X3Zhcl8zMCRNQ29WTnVtYmVyICU+JSB1bmlxdWUgJT4lIGxlbmd0aCkqMC4wMSkgJT4lIHB1bGwobnRwb3MpCgoKKCgKICBoc3NfbWFmPC1wYXRpZW50X3Zhcl8zMCAlPiUgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gYXMuZmFjdG9yKG50cG9zKSwgeSA9IG1pbm9yZnJlcSkpICsgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMSkpICsgdGhlbWVfYncoKSArIAogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPTAuNSkgKyAKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkgKyAjZ2VvbV9ib3hwbG90KG91dGxpZXIuYWxwaGEgPSAwKSArIAogICAgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsgeWxhYigiTWlub3IgYWxsZWxlIGZyZXEiKSArIAogICAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSJsb2cyIiwgYnJlYWtzID0gYygwLjAxKjJeKDA6NSksIDAuNSkpCiAgKSkKCmdnc2F2ZSgiZ2dzYXZlL2hzc19tYWYucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLCBwbG90ID0gaHNzX21hZikKCigoCiAgaHNzX21hZl91bmxvZzwtcGF0aWVudF92YXJfMzAgJT4lIGZpbHRlcihudHBvcyAlaW4lIGhpZ2hseV9zaGFyZWRfc2l0ZXMpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IGFzLmZhY3RvcihudHBvcyksIHkgPSBtaW5vcmZyZXEpKSArIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEpKSArIHRoZW1lX2J3KCkgKyAKICAgIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC41KSArIAogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApKSArICNnZW9tX2JveHBsb3Qob3V0bGllci5hbHBoYSA9IDApICsgCiAgICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKyB5bGFiKCJNaW5vciBhbGxlbGUgZnJlcSIpICMrIAogICAgI3NjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMiIsIGJyZWFrcyA9IGMoMC4wMSoyXigwOjUpLCAwLjUpKQogICkpCmdnc2F2ZSgiZ2dzYXZlL2hzc19tYWZfdW5sb2cucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLCBwbG90ID0gaHNzX21hZl91bmxvZykKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTB9CiNIb3cgbWFueSBkaWZmZXJlbnQgY2hhbmdlcyBkbyB5b3UgZmluZCBhdCBlYWNoIHJlY3VycmVudGx5LW11dGF0ZWQgcG9zaXRpb24/IEhvdyBtYW55IHN1Y2ggbXV0YXRpb25zIGFyZSBhIHJldmVyc2lvbiB0byB0aGUgcmVmZXJlbmNlPwpoc3NfaW5mbyA8LSBmcmVhZCgnaHNzX2RhdGEyLmNzdicsIGRhdGEudGFibGUgPSBGKQoKKCgKICBoc3NfcGxvdCA9IHBhdGllbnRfdmFyXzMwX2Zvcl9yYW5rICU+JSBtdXRhdGUobGFiZWxfZ2VuZSA9IHBhc3RlMChnZW5lLCAiOiAiLCBsYWJlbCkpICU+JQogICAgZmlsdGVyKG50cG9zICVpbiUgaGlnaGx5X3NoYXJlZF9zaXRlcykgJT4lIAogICAgZ3JvdXBfYnkobnRwb3MsIG1ham9yLCBtaW5vcikgJT4lIG11dGF0ZShuPW4oKSwgbWVkaWFuX2ZyZXF1ZW5jeSA9IG1lZGlhbihtaW5vcmZyZXEpKSAlPiUgICAgIG11dGF0ZShjaGFuZ2U9cGFzdGUwKG1ham9yLCI+IixtaW5vcikpICU+JSAKICAgIG11dGF0ZShyZWZfcmV2ZXJzaW9uPWlmX2Vsc2UobWlub3I9PXJlZm50LCJ5ZXMiLCJubyIpKSAlPiUgCiAgICBtdXRhdGUobWVkaWFuX01BRj1pZl9lbHNlKG1lZGlhbl9mcmVxdWVuY3k8MC4wMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsb3cgKG1lZGlhbiA8MiUgTUFGKSIsImhpZ2ggKG1lZGlhbiA+PTIlIE1BRikiKSkgJT4lCiAgICBzZWxlY3QoY2hhbmdlLCBuLCByZWZfcmV2ZXJzaW9uLCBudHBvcywgbGFiZWxfZ2VuZSwgbWVkaWFuX01BRikgJT4lIGRpc3RpbmN0ICU+JQogICAgZ2dwbG90KGFlcyh4PWNoYW5nZSwgeT1uLCBjb2xvcj1yZWZfcmV2ZXJzaW9uKSkgKyAKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWVzKGZpbGw9bWVkaWFuX01BRikpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIndoaXRlIiwicmVkIikpICsgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZGFya21hZ2VudGEiLCJzdGVlbGJsdWUiKSkgKyAKICAgIGZhY2V0X3dyYXAobnRwb3N+bGFiZWxfZ2VuZSwgc2NhbGVzPSJmcmVlIikgKyAKICAgIHRoZW1lX3B1YnIoKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCkpCikpCgpnZ3NhdmUoJ2dnc2F2ZS9oc3NfcGxvdC5wZGYnLCBwbG90ID0gaHNzX3Bsb3QsIHdpZHRoID0gMTEsIGhlaWdodCA9IDEzKQpgYGAKCgpgYGB7cn0KbGRtX3ZlY3RvciA9IGxpbmVhZ2VfZGVmaW5pbmdfbXV0YXRpb25zJG50X3BvcwpoZWF0bWFwX3NwZWN0cmFfdG1wID0gcGF0aWVudF92YXJfMzBfZm9yX3JhbmsgJT4lIAogIG11dGF0ZShsYWJlbF9nZW5lID0gcGFzdGUwKGdlbmUsICI6ICIsIGxhYmVsKSkgJT4lCiAgICBmaWx0ZXIobnRwb3MgJWluJSBoaWdobHlfc2hhcmVkX3NpdGVzKSAlPiUgCiAgICBncm91cF9ieShudHBvcywgbWFqb3IsIG1pbm9yKSAlPiUgbXV0YXRlKG49bigpLCBtZWRpYW5fZnJlcXVlbmN5ID0gbWVkaWFuKG1pbm9yZnJlcSkpICU+JQogIG11dGF0ZShjaGFuZ2U9cGFzdGUwKG1ham9yLCI+IixtaW5vciksIAogICAgICAgICB0cmFuc2l0aW9uID0gaWZlbHNlKGNoYW5nZSAlaW4lIGMoIkM+VCIsIlQ+QyIsIkE+RyIsIkc+QSIpLCAxLCAwKSkgJT4lCiAgICAgbXV0YXRlKHJlZl9yZXZlcnNpb249aWZfZWxzZShtaW5vcj09cmVmbnQsMSwwKSkgJT4lIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoY2hhbmdlLCBuLCBudHBvcywgbGFiZWxfZ2VuZSkgJT4lIGRpc3RpbmN0ICU+JSAKICBncm91cF9ieShudHBvcykgJT4lIG11dGF0ZShudHBvc19uID0gc3VtKG4pKSAlPiUgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3Byb3AgPSBuL250cG9zX24pICU+JSBzZWxlY3QoLW4pICU+JSAKICBtdXRhdGUobGRtID0gYXMuZmFjdG9yKGlmZWxzZShudHBvcyAlaW4lIGxkbV92ZWN0b3IsIDEsIDApKSkgJT4lCiAgbXV0YXRlKGxhYmVsID0gcGFzdGUwKGxhYmVsX2dlbmUsICIgLSAiLCBudHBvcywgIiAoIiwgbnRwb3NfbiwgIikiKSkKCgphbm5vdGF0aW9uX3Jvd19kZiA9IGhlYXRtYXBfc3BlY3RyYV90bXAgJT4lIHNlbGVjdChsYWJlbCwgbGRtKSAlPiUgCiAgZGlzdGluY3QgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImxhYmVsIikKYW5ub3RhdGlvbl9yb3dfZGYKIyU+JQpoZWF0bWFwX3NwZWN0cmEgPSBoZWF0bWFwX3NwZWN0cmFfdG1wICU+JSBzZWxlY3QoLWxkbSkgJT4lIHNwcmVhZChjaGFuZ2UsIG5fcHJvcCkgJT4lIAogIGFycmFuZ2UoLW50cG9zX24pICU+JSBkaXN0aW5jdCgpICU+JSAgCiAgc2VsZWN0KC1jKG50cG9zLCBsYWJlbF9nZW5lLCBudHBvc19uKSkgJT4lIHJlcGxhY2UoLixpcy5uYSguKSwwKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImxhYmVsIikKCmFubm90YXRpb25fY29sX2RmID0gaGVhdG1hcF9zcGVjdHJhX3RtcCAlPiUgc2VsZWN0KGNoYW5nZSkgJT4lIGRpc3RpbmN0ICU+JSAKICBtdXRhdGUodHJhbnN2ZXJzaW9uID0gCiAgICAgICAgICAgYXMuZmFjdG9yKGlmZWxzZSghKGNoYW5nZSAlaW4lIGMoIkM+VCIsIlQ+QyIsIkE+RyIsIkc+QSIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAwKSkpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoImNoYW5nZSIpCgptYWYgPSBoZWF0bWFwX3NwZWN0cmFfdG1wICU+JSBzZWxlY3QobnRwb3MsIGxhYmVsKSAlPiUgZGlzdGluY3QgJT4lCiAgbGVmdF9qb2luKHBhdGllbnRfdmFyXzMwICU+JSBzZWxlY3QobnRwb3MsIG1pbm9yZnJlcSkpICU+JSAKICBzZWxlY3QobGFiZWwsIG1pbm9yZnJlcSkKbWFmX2xpc3QgPSBzcGxpdChtYWYkbWlub3JmcmVxLG1hZiRsYWJlbCkKCnJvd19oYSA9IHJvd0Fubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKAogIGxkbSA9IGFubm90YXRpb25fcm93X2RmW3Jvd25hbWVzKGhlYXRtYXBfc3BlY3RyYSksXSksIAogIGNvbCA9IGxpc3QobGRtID0gYyhgMWA9ImdyZXkiLCBgMGA9IndoaXRlIikpLAogIE1BRiA9IGFubm9fYm94cGxvdChtYWZfbGlzdCwgcGNoID0gMjAsIHNpemUgPSB1bml0KDAuNSwgIm1tIikpKQoKCmhlYXRtYXBfc3BlY3RyYV9yZW9yZGVyID0gaGVhdG1hcF9zcGVjdHJhICU+JSBzZWxlY3QoYygiQT5HIiwiRz5BIiwiQz5UIiwiVD5DIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQT5DIiwgIkM+QSIsICJBPlQiLCAiVD5BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQz5HIiwgIkc+QyIsICJHPlQiLCAiVD5HIikpCmNvbF9oYSA9IGNvbHVtbkFubm90YXRpb24oZGYgPSBkYXRhLmZyYW1lKAogIHRyYW5zdmVyc2lvbiA9IGFubm90YXRpb25fY29sX2RmW2NvbG5hbWVzKGhlYXRtYXBfc3BlY3RyYV9yZW9yZGVyKSxdKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdCh0cmFuc3ZlcnNpb24gPSBjKGAxYD0iZ3JleSIsIGAwYD0id2hpdGUiKSkpCgpoZWF0bWFwX3NwZWN0cmFfaHNzID0gSGVhdG1hcChoZWF0bWFwX3NwZWN0cmFfcmVvcmRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJwcm9wL3NpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIndoaXRlIiwgImJyb3duNCIpKSgxMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEYsIGxlZnRfYW5ub3RhdGlvbiA9IHJvd19oYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjdF9ncCA9IGdwYXIoY29sID0gImdyZXk5MCIsIGx3ZCA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGNvbF9oYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KGRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpKSAKCnBkZihxcSgiZ2dzYXZlL2hlYXRtYXBfc3BlY3RyYV9oc3MucGRmIiksIHdpZHRoID0gNi41LCBoZWlnaHQgPSA3KQpkcmF3KGhlYXRtYXBfc3BlY3RyYV9oc3MsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIAogICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAicmlnaHQiLCAKICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAicmlnaHQiKQpkZXYub2ZmKCkKCmhlYXRtYXBfc3BlY3RyYV9oc3MKIyAKIyAgICAgICAgICAgYm9yZGVyX2NvbG9yID0gImdyZXk5MCIsIGNvbG9yUmFtcFBhbGV0dGUoYygid2hpdGUiLCAiYnJvd240IikpKDEwMCksCiMgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSAwLCB0cmVlaGVpZ2h0X2NvbCA9IDEwLCBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb25fY29sX2RmLAojICAgICAgICAgIGFubm90YXRpb25fcm93ID0gYW5ub3RhdGlvbl9yb3dfZGYsIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvcnMpCiMgcGFjbWFuOjpwX2xvYWQoQ29tcGxleEhlYXRtYXApCiAgICAgICAgIApgYGAKCmBgYHtyfQojYWxsIG1pbm9yIHZhcmlhbnRzIHRoYXQgYXJlIGZvdW5kIGluIGF0IGxlYXN0IDIlIG9mIGhpZ2gtY292ZXJhZ2Ugc2FtcGxlcyBpbiBMeXRoZ29lIGV0IGFsIGh0dHBzOi8vd3d3LnNjaWVuY2Uub3JnL2RvaS9zdXBwbC8xMC4xMTI2L3NjaWVuY2UuYWJnMDgyMS9zdXBwbF9maWxlL2FiZzA4MjEtbHl0aGdvZS1zbS5wZGYKbHl0aGdvZV9oc3M8LWMoMjkzMjAsIDI1NjI4LCAyNTgwNywgMjAzNjQsIDM1NywgMjU2MjcsIDI1NTMyLCAxMTA4MywgMjM5LCAyMzgsIDM1NiwgMTY3NDAsIDIwOTg5LCAxOTM5MywgMTUwMDksIDIxODI2LCAxOTkzNywgMjYyODksMjgyNTMsMjU1MDcsMjk4NjIsMTEwNTIsMjk4NjQsMjU1MjksMzY5LDIyNDUzLDEzNTcxLDI5NTM4LDIxNTc1LDc1LDIwOTkzLDE5NDczLDE1NDc0LDYzNSwxMjI2LDI5NzQ3LDI0OTMzLDE5MjEwLDEzMzAzLDI4OTM2LDI2MzM0LDE2ODg3KQoKdG9ua2luX2hzczwtYygxMTA3NUwsIDExMDgzTCwgMTEwNzRMLCA1MjJMLCAyNjc4MEwsIDE1NDdMLCAxNDQwOEwsIDI4MjUzTCwgMTM5MTRMLCAyNjEzN0wsIDYzNUwsIDI0MUwsIDI2Nzg1TCwgNjgzTCwgMjM0MDNMLCAyODg4MUwsIDEzNzc4TCwgMjU1MjFMLCAxNDgwNUwsIDk0OTFMLCAxMTA3MUwsIDEzNzgwTCwgMjE1NzVMLCAyOTI0MkwsIDk0MzBMLCAyMDNMLCAzMDM3TCwgNjg2TCwgMzA5NkwsIDE2Mzc1TCwgMTY0NjZMLCAxNzE2N0wsIDIzNTU5TCwgOTQzOEwsIDIxMTM3TCwgMjkwNTFMLCAyMzU1NUwsIDI2MzMzTCwgOTQ3NEwsIDEzNTcxTCwgMTY4ODdMLCAyNjc4N0wsIDI4NjAzTCwgMjQyMTNMLCAxMTY1MUwsIDI3OTI1TCwgNTE0TCwgMjY3ODFMLCA1NThMLCAxOTEyTCwgOTQ3OUwsIDExMDczTCwgMTI1NzhMLCAyNjE0NEwsIDI2NjgxTCwgMjkyNDFMKQppbnRlcnNlY3QobHl0aGdvZV9oc3MsIGhpZ2hseV9zaGFyZWRfc2l0ZXMpCmludGVyc2VjdCh0b25raW5faHNzLCBoaWdobHlfc2hhcmVkX3NpdGVzKQpgYGAKCmBgYHtyfQpob21vcGxhc2ljX3NpdGVfbGlzdDwtYygxODdMLCAxMDU5TCwgMjA5NEwsIDMwMzdMLCAzMTMwTCwgNjk5MEwsIDgwMjJMLCAxMDMyM0wsIDEwNzQxTCwgMTEwNzRMLCAxMTA4M0wsIDEzNDA4TCwgMTQ3ODZMLCAxNTMyNEwsIDE5Njg0TCwgMjAxNDhMLCAyMTEzN0wsIDIxNTc1TCwgMjQwMzRMLCAyNDM3OEwsIDI1NTYzTCwgMjYxNDRMLCAyNjQ2MUwsIDI2NjgxTCwgMjgwNzdMLCAyODgyNkwsIDI4ODU0TCwgMjk3MDBMKQppbnRlcnNlY3QoaG9tb3BsYXNpY19zaXRlX2xpc3QsIGhpZ2hseV9zaGFyZWRfc2l0ZXMpCmBgYAoKYGBge3J9CnRhbGx5X2luX21pbm9yczwtcGF0aWVudF92YXJfMzAgJT4lIGZpbHRlcihudHBvcyAlaW4lIGhpZ2hseV9zaGFyZWRfc2l0ZXMpICU+JSBncm91cF9ieShudHBvcykgJT4lIHN1bW1hcmlzZShuX21pbm9yX3ZhcmlhbnRzX2hvdXN0b249bigpKSAlPiUgbXV0YXRlKGZyZXFfbWlub3JfdmFyaWFudHNfaG91c3Rvbj1uX21pbm9yX3ZhcmlhbnRzX2hvdXN0b24vbnJvdyhwYXRpZW50X2NvdW50c18zMCkpCgp0YWxseV9pbl9naXNhaWQ8LWZyZWFkKCdoc3NfZ2lzYWlkX3RhbGxpZXMuY3N2JywgZGF0YS50YWJsZSA9IEYpICU+JSBzZWxlY3QobnRwb3MsIG5fY29uc2Vuc3VzX3ZhcmlhbnRzX2dpc2FpZD1uKSAlPiUgbXV0YXRlKGZyZXFfY29uc2Vuc3VzX3ZhcmlhbnRzX2dpc2FpZD1uX2NvbnNlbnN1c192YXJpYW50c19naXNhaWQvMzEwOTQyMSkgI1VTQSBnaXNhaWQgc2VxdWVuY2VzIGFzIG9mIDYvMTMvMjAyMgojU1VQUCBGSUcgMTAKCnRhbGx5X2luX21pbm9yc19naXNhaWQgPSBmcmVhZCgicHJvY2Vzc2luZy90YWxseV9pbl9taW5vcnMudHh0IiwgZGF0YS50YWJsZSA9IEYpICU+JSAKICBsZWZ0X2pvaW4obWlub3JfY29uc2Vuc3VzX3Bsb3RkYXRhKSAlPiUgbXV0YXRlKGxkbSA9IGFzLmZhY3Rvcihjb25zZW5zdXMpKQoKdGFsbHlfaW5fbWlub3JzX2dpc2FpZAooKAogIGdpc2FpZF92c19obWhfcGxvdCA9ICN0YWxseV9pbl9taW5vcnMgJT4lIGxlZnRfam9pbiggdGFsbHlfaW5fZ2lzYWlkKSAlPiUgCiAgICAKICAgIHRhbGx5X2luX21pbm9yc19naXNhaWQgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZnJlcV9taW5vcl92YXJpYW50c19ob3VzdG9uLCB5PWZyZXFfY29uc2Vuc3VzX3ZhcmlhbnRzX2dpc2FpZCwgCiAgICAgICAgICAgICAgIGNvbG9yID0gbGRtKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyAKICAgIHRoZW1lX3B1YnIobGVnZW5kPSAicmlnaHQiKSArIAogIHhsYWIoIkZyYWN0aW9uIG9mIHNhbXBsZXMgd2l0aCBtaW5vciB2YXJpYW50IGluIEhvdXN0b24gZGF0YSIpICsgCiAgICB5bGFiKCJGcmFjdGlvbiBvZiBzYW1wbGVzIHdpdGggXG4gY29uc2Vuc3VzIHZhcmlhbnQgaW4gR0lTQUlEIEdsb2JhbCIpICsgCiAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPW50cG9zKSwgbWF4Lm92ZXJsYXBzID0gMTAsIGxhYmVsLnNpemU9MC4xKSArIAogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0iZGFzaGVkIiwgY29sb3IgPSAiZ3JheSIpICsKICAgIHNjYWxlX3lfY29udGludW91cyh0cmFucz0ibG9nMTAiKSArIHNjYWxlX3hfY29udGludW91cyh0cmFucz0ibG9nMTAiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQopKQoKZ2lzYWlkX3ZzX2htaF9tYXJnaW5hbCA9IGdnTWFyZ2luYWwoZ2lzYWlkX3ZzX2htaF9wbG90LAogICAgICAgICAgICAgZ3JvdXBDb2xvdXIgPSBULAogIGdyb3VwRmlsbCA9IFQpCgpnZ3NhdmUoImdnc2F2ZS9naXNhaWRfdnNfaG1oX3Bsb3RfbWFyZ2luYWwucGRmIiwgcGxvdCA9IGdpc2FpZF92c19obWhfbWFyZ2luYWwsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDZ9CiMgTVVUQVRJT04gU1BFQ1RSQSBBTkFMWVNJUwoKIyByZXByb2R1Y2liaWxpdHkgYW5hbHlzaXMgZnJvbSBSTUQgMDEKcGxvdF9ub25yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwID0gcmVhZFJEUyhmaWxlID0gInBsb3Rfbm9ucmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcC5yZHMiKQpwbG90X3JlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAgPSByZWFkUkRTKGZpbGUgPSAicGxvdF9yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwLnJkcyIpCgpobWFwPC10YWJsZShwYXRpZW50X3Zhcl8zMCRtYWpvcltwYXRpZW50X3Zhcl8zMCRtYWpvciE9IiJdLCBwYXRpZW50X3Zhcl8zMCRtaW5vcltwYXRpZW50X3Zhcl8zMCRtaW5vciE9IiJdKSAlPiUgZGF0YS5mcmFtZSgpICU+JQogIGdncGxvdChhZXMoeD1WYXIxLCB5PVZhcjIsIGZpbGw9RnJlcS9zdW0oRnJlcSkpKSArIGdlb21fdGlsZShjb2xvdXIgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJkYXJrYmx1ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgIGxhYnMoZmlsbCA9ICJOdW1iZXIiLAogICAgICAgeCA9ICJDb25zZW5zdXMgYWxsZWxlIiwKICAgICAgIHkgPSAiTWlub3IgYWxsZWxlIiwgdGl0bGUgPSAiUG9zdC1zYW1wbGUgZmlsdGVyIChDdCwgbl92YXIpIikgI01vc3QgZnJlcXVlbnRseSBDPlQgbXV0YXRpb25zCgojIE5vdyBiZWVjYXVzZSBzb21lIHBlYWtzIGFyZSByZWFsbHkgcHJldmFsZW50IGxpa2UgdGhlIHR3aW4gcGVha3MgYXQgMjkxODcvOCwgCiMgaXQncyBpbXBvcnRhbnQgdG8gbm90IGZhY3RvciB0aGF0IGluIHRvbyBtdWNoLiBTbyBsZXQncyBqdXN0IGFzc2lnbiB0aG9zZSBtdXRhdGlvbnMKIyB0byBlcXVhdGUgdG8gdGhlIG1lZGlhbiBudW1iZXIgYSBtdXRhdGlvbiBhcHBlYXJzIHdoaWNoIGlzIDEuCgptdXRhdGlvbl9zcGVjdHJhID0gcGF0aWVudF92YXJfMzAgJT4lIHVuaXRlKGNvbCA9ICJzcGVjdHJhX211dGF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFqb3IsIG50cG9zLCBtaW5vciwgcmVtb3ZlID0gRkFMU0UpCm11dGF0aW9uX3NwZWN0cmFfY291bnRzID0gbXV0YXRpb25fc3BlY3RyYSAlPiUgY291bnQoc3BlY3RyYV9tdXRhdGlvbikKCm11dGF0aW9uX3NwZWN0cmFfY291bnRzICU+JSBnZ3Bsb3QoYWVzKHk9bikpICsgZ2VvbV9ib3hwbG90KCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAibG9nMXAiKQoKbXV0YXRpb25fc3BlY3RyYV9jb3VudHMkbiAlPiUgcXVhbnRpbGUoKSAjIG1lZGlhbiBpcyAxCgptdXRhdGlvbl9zcGVjdHJhX3VuaXF1ZSA9IG11dGF0aW9uX3NwZWN0cmEgJT4lIAogIHNlbGVjdChtYWpvciwgbWlub3IsIHNwZWN0cmFfbXV0YXRpb24pICU+JSB1bmlxdWUoKQoKaG1hcF91bmlxdWUgPC10YWJsZShtdXRhdGlvbl9zcGVjdHJhX3VuaXF1ZSRtYWpvclttdXRhdGlvbl9zcGVjdHJhX3VuaXF1ZSRtYWpvciE9IiJdLCBtdXRhdGlvbl9zcGVjdHJhX3VuaXF1ZSRtaW5vclttdXRhdGlvbl9zcGVjdHJhX3VuaXF1ZSRtaW5vciE9IiJdKSAlPiUgZGF0YS5mcmFtZSgpICU+JQogIGdncGxvdChhZXMoeD1WYXIxLCB5PVZhcjIsIGZpbGw9RnJlcS9zdW0oRnJlcSkpKSArIGdlb21fdGlsZShjb2xvdXIgPSAiYmxhY2siKSArICMgZ3JpZCBjb2xvcgogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobGltaXRzID0gYygwLDAuNCksIGxvdyA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtibHVlIikgKwogIHRoZW1lX21pbmltYWwoKSArICAgbGFicyhmaWxsID0gIkZyYWN0aW9uIiwKICAgICAgIHggPSAiQ29uc2Vuc3VzIGFsbGVsZSIsCiAgICAgICB5ID0gIk1pbm9yIGFsbGVsZSIsIHRpdGxlPSJVbmlxdWUgbWlub3IgdmFyaWFudHMiKQoKcmVzY2FsZV9maWxsID0gZnVuY3Rpb24oaG1hcF91bmlxdWUpIHsKICBobWFwX3VuaXF1ZV9yZXNjYWxlZCA9IGhtYXBfdW5pcXVlICsgCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxpbWl0cyA9IGMoMCwwLjQpLCBsb3cgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJkYXJrYmx1ZSIpICsKICAgIGdlb21fbGFiZWwoZmlsbCA9ICJ3aGl0ZSIsIGFscGhhID0gMC4zLCBhZXMoeCA9IFZhcjEsIHkgPSBWYXIyLCBsYWJlbCA9IHJvdW5kKEZyZXEvc3VtKEZyZXEpLCBkaWdpdHMgPSAyKSkpCiAgcmV0dXJuKGhtYXBfdW5pcXVlX3Jlc2NhbGVkKQp9CgooKAogIHJlcF9udWNsZW90aWRlcyA9IGdnYXJyYW5nZShyZXNjYWxlX2ZpbGwocGxvdF9ub25yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2NhbGVfZmlsbChwbG90X3JlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzY2FsZV9maWxsKGhtYXApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzY2FsZV9maWxsKGhtYXBfdW5pcXVlKSwgY29tbW9uLmxlZ2VuZCA9IFQpCikpCnJlcF9udWNsZW90aWRlcwoKZ2dzYXZlKCJnZ3NhdmUvaGVhdG1hcF9zcGVjdHJhX3JlcGxpY2F0ZV92YXJpYW50cy5wZGYiLCByZXBfbnVjbGVvdGlkZXMsIGhlaWdodCA9IDYsIHdpZHRoID0gNikKYGBgCg==